{{>partial_header}}
{{#operations}}

{{#operation}}
function {{operationId}}_read(handler)
    function {{operationId}}_read_handler(req::HTTP.Request)
        openapi_params = Dict{String,Any}(){{#hasPathParams}}
        path_params = HTTP.getparams(req){{#pathParams}}
        openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, path_params, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/pathParams}}{{/hasPathParams}}{{#hasQueryParams}}
        query_params = HTTP.queryparams(URIs.URI(req.target)){{#queryParams}}
        openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, query_params, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{#required}}required=true, {{/required}}style="{{style}}", is_explode={{isExplode}}{{#isListContainer}},collection_format="{{collectionFormat}}"{{/isListContainer}}){{/queryParams}}{{/hasQueryParams}}{{#hasHeaderParams}}
        headers = Dict{String,String}(HTTP.headers(req)){{#headerParams}}
        openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, headers, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/headerParams}}{{/hasHeaderParams}}{{#hasBodyParam}}{{#bodyParams}}
        openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param_type({{dataType}}, String(req.body)){{/bodyParams}}{{/hasBodyParam}}{{#hasFormParams}}
        ismultipart = {{#isMultipart}}true{{/isMultipart}}{{^isMultipart}}false{{/isMultipart}}
        form_data = ismultipart ? HTTP.parse_multipart_form(req) : HTTP.queryparams(String(copy(req.body))){{#formParams}}
        openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{#dataType}}{{#isBinary}}Vector{UInt8}{{/isBinary}}{{^isBinary}}{{dataType}}{{/isBinary}}{{/dataType}}, form_data, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"; multipart=ismultipart, isfile={{#isFile}}true{{/isFile}}{{^isFile}}false{{/isFile}}, {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/formParams}}{{/hasFormParams}}
        req.context[:openapi_params] = openapi_params

        return handler(req)
    end
end

function {{operationId}}_validate(handler)
    function {{operationId}}_validate_handler(req::HTTP.Request)
        openapi_params = req.context[:openapi_params]
        op = "{{operationId}}"{{#allParams}}
        
        n = "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"
        v = get(openapi_params, n, nothing){{#required}}
        isnothing(v) && throw(OpenAPI.ValidationException(;reason="missing parameter $n", operation_or_model=op)){{/required}}
        if !isnothing(v){{#hasValidation}}{{#maxLength}}
            OpenAPI.validate_param(n, op, :maxLength, v, {{maxLength}}){{/maxLength}}{{#minLength}}
            OpenAPI.validate_param(n, op, :minLength, v, {{minLength}}){{/minLength}}{{#maximum}}
            OpenAPI.validate_param(n, op, :maximum, v, {{maximum}}, {{#exclusiveMaximum}}true{{/exclusiveMaximum}}{{^exclusiveMaximum}}false{{/exclusiveMaximum}}){{/maximum}}{{#minimum}}
            OpenAPI.validate_param(n, op, :minimum, v, {{minimum}}, {{#exclusiveMinimum}}true{{/exclusiveMinimum}}{{^exclusiveMinimum}}false{{/exclusiveMinimum}}){{/minimum}}{{#maxItems}}
            OpenAPI.validate_param(n, op, :maxItems, v, {{maxItems}}){{/maxItems}}{{#minItems}}
            OpenAPI.validate_param(n, op, :minItems, v, {{minItems}}){{/minItems}}{{#uniqueItems}}
            OpenAPI.validate_param(n, op, :uniqueItems, v, {{uniqueItems}}){{/uniqueItems}}{{#maxProperties}}
            OpenAPI.validate_param(n, op, :maxProperties, v, {{maxProperties}}){{/maxProperties}}{{#minProperties}}
            OpenAPI.validate_param(n, op, :minProperties, v, {{minProperties}}){{/minProperties}}{{#pattern}}
            OpenAPI.validate_param(n, op, :pattern, v, r"{{{pattern}}}"){{/pattern}}{{#multipleOf}}
            OpenAPI.validate_param(n, op, :multipleOf, v, {{multipleOf}}){{/multipleOf}}{{/hasValidation}}{{^hasValidation}}
            if isa(v, OpenAPI.APIModel)
                OpenAPI.validate_properties(v)
                if !OpenAPI.check_required(v)
                    throw(OpenAPI.ValidationException(;reason="$n is missing required properties", operation_or_model=op))
                end
            end{{/hasValidation}}
        end{{/allParams}}

        return handler(req)
    end
end

function {{operationId}}_invoke(impl; post_invoke=nothing)
    function {{operationId}}_invoke_handler(req::HTTP.Request)
        openapi_params = req.context[:openapi_params]
        ret = impl.{{operationId}}(req::HTTP.Request{{#allParams}}{{#required}}, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"]{{/required}}{{/allParams}};{{#allParams}}{{^required}} {{paramName}}=get(openapi_params, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", nothing),{{/required}}{{/allParams}})
        resp = OpenAPI.Servers.server_response(ret)
        return (post_invoke === nothing) ? resp : post_invoke(req, resp)
    end
end

{{/operation}}

function register{{classname}}(router::HTTP.Router, impl; path_prefix::String="", optional_middlewares...)
    {{#operation}}
    HTTP.register!(router, "{{httpMethod}}", path_prefix * "{{{path}}}", OpenAPI.Servers.middleware(impl, {{operationId}}_read, {{operationId}}_validate, {{operationId}}_invoke; optional_middlewares...))
    {{/operation}}
    return router
end
{{/operations}}